<template>
  <div class="video-box">
    <!-- 缓存进度 @progress="onPorgressChange" -->
    <video
      ref="myVideo"
      poster=""
      preload="auto"
      webkit-playsinline="true"
      playsinline="true"
      x5-video-player-type="h5-page"
      :src="props.url"
      :playbackRate="speedList[currentSpeedIdx].val"
      :volume="currentVolume"
      :class="{ 'full-screen': isFullScreen }"
      @click="onVideoPlayOrPause"
      @play="onVideoPlay"
      @pause="onVideoPause"
      @durationchange="onDurationchange"
      @timeupdate="onTimeupdate"
    >
    </video>
    <span v-show="showPlayButton" class="play-btn" @click="onVideoPlayOrPause"></span>
    <span v-show="showPlayButton" class="pause-mask" @click="onVideoPlayOrPause"></span>
    <span v-show="showLoading" class="icon-loading"></span>
    <div class="video-bottom-box">
      <div class="video-control">
        <span
          :class="['bottom-btn', isPlaying ? 'pause' : 'play']"
          @click="onVideoPlayOrPause"
        ></span>
        <span class="time-text play-time">{{ currentTimes }}</span>
        <div ref="progressBarBox" class="progress-bar-box" @click="onPorgressBarClick">
          <span class="progress-bar-main"></span>
          <span ref="progressBarBall" class="progress-bar-ball" @mousedown="onDragBall"></span>
          <!-- <span class="progress-bar-load"></span> -->
        </div>
        <span class="time-text">{{ durationTimes }}</span>
        <div class="play-speed">
          {{ currentSpeedIdx !== 2 ? speedList[currentSpeedIdx].label : '倍速' }}
          <div class="speed-list">
            <div class="inner">
              <div
                v-for="(item, idx) in speedList"
                :key="idx"
                :class="['speed-item', { actived: idx === currentSpeedIdx }]"
                @click.stop="onVideoSpeedChange(idx)"
              >
                {{ item.label }}
              </div>
            </div>
          </div>
        </div>
        <div ref="voiceBoxRef" :class="['bottom-btn', 'voice', { mute: currentVolume === 0 }]">
          <div class="voice-container">
            <div class="inner">
              <div
                ref="voiceProgressBox"
                class="voice-progress-bar"
                @click="onVoicePorgressBarClick"
              >
                <span class="progress-bar-main"></span>
                <span class="progress-bar-ball" @mousedown="onDragVoiceBall"></span>
              </div>
            </div>
          </div>
        </div>
        <span
          :class="['bottom-btn', 'full-screen', { quit: isFullScreen }]"
          @click="onVideoFunllScreenChange"
        ></span>
      </div>
    </div>
  </div>
</template>

<script setup>
import { ref, defineProps, defineExpose, defineEmits } from 'vue';
import { getEleOffsetLeft, getEleOffsetTop } from '@/util/dom';
import { getTimesBySecond } from '@/util/utils';

let props = defineProps({
  url: {
    type: String
  },
  currentTime: {
    type: String
  },
  width: {
    type: String,
    default: 'auto'
  },
  height: {
    type: String,
    default: 'auto'
  }
});

let emits = defineEmits(['onFullScreenChange']);

// dom节点
const myVideo = ref(null); // 视频
const progressBarBox = ref(); // 视频播放进度条
const progressBarBall = ref(); // 滑块
// 状态按钮显示隐藏
const showPlayButton = ref(true);
const isPlaying = ref(false);
const showLoading = ref(false);
// 视频时间
const currentTimes = ref('00:00');
const durationTimes = ref('00:00');
// 进度条、滑块位置控制
const progressBarMainW = ref(0);
const progressBarBallLeft = ref('-10px');
// const progressBarLoadW = ref(0);

// 根据视频状态执行播放、暂停方法
function onVideoPlayOrPause() {
  if (myVideo.value?.paused) {
    myVideo.value?.play();
  } else {
    myVideo.value?.pause();
  }
}

// 监听视频播放暂停状态
function onVideoPlay() {
  showPlayButton.value = false;
  showLoading.value = true;
  isPlaying.value = true;
}
function onVideoPause() {
  showPlayButton.value = true;
  showLoading.value = false;
  isPlaying.value = false;
}
// 更新视频总时长
function onDurationchange() {
  durationTimes.value = getTimesBySecond(myVideo.value?.duration);
}
// 更新缓存进度
// function onPorgressChange() {
//   progressBarLoadW.value = `${
//     (Math.floor(myVideo.value?.buffered.end(0)) / Math.floor(myVideo.value?.duration)) * 100
//   }%`;
// }
// 视频播放进度监听
function onTimeupdate() {
  // 根据视频状态判断是否loading
  if (myVideo.value?.readyState < 3 && !myVideo.value?.paused) {
    showLoading.value = true;
  } else {
    showLoading.value = false;
  }
  // 设置播放进度
  setPlayProgress(myVideo.value?.currentTime);
}
// 单击进度条改变播放进度
function onPorgressBarClick(event) {
  const clientX = event.clientX;
  const offsetX = getEleOffsetLeft(progressBarBox.value);
  const totalW = progressBarBox.value.offsetWidth;
  const currentW = clientX - offsetX;
  let curTimes = (currentW / totalW) * myVideo.value?.duration;
  // 非暂停状态触发loading
  if (!myVideo.value?.paused) {
    showLoading.value = true;
  }
  // 设置播放进度
  setPlayProgress(curTimes);
  myVideo.value.currentTime = curTimes;
}
// 拖动滑块
function onDragBall(event) {
  event.preventDefault();
  document.onmousemove = e => {
    e.preventDefault();
    let parentX = getEleOffsetLeft(progressBarBox.value);
    let totalW = progressBarBox.value.offsetWidth;
    // 获取滑块在盒子内的坐标
    let moveW = e.clientX - parentX;
    moveW = moveW <= 0 ? 0 : moveW >= totalW ? totalW : moveW;
    // 更新视频当前播放时间
    let curTimes = (moveW / totalW) * myVideo.value?.duration;
    if (!myVideo.value?.paused) {
      showLoading.value = true;
    }
    // 设置播放进度
    setPlayProgress(curTimes);
    myVideo.value.currentTime = curTimes;
  };
  // 抬起鼠标，结束移动事件
  document.onmouseup = () => {
    document.onmousemove = null;
    document.onmouseup = null;
  };
}
// 设置播放进度
function setPlayProgress(curTimes) {
  let progress = `${(Math.floor(curTimes) / Math.floor(myVideo.value?.duration)) * 100}%`;
  progressBarMainW.value = progress;
  progressBarBallLeft.value = `calc(${progress} - ${progressBarBall.value.offsetWidth / 2}px)`;
  // 更新实时播放时间
  currentTimes.value = getTimesBySecond(curTimes);
}

// 倍速控制
const speedList = [
  { label: '2.0x', val: 2 },
  { label: '1.5x', val: 1.5 },
  { label: '1.0x', val: 1 },
  { label: '0.5x', val: 0.5 }
];
const currentSpeedIdx = ref(2);
function onVideoSpeedChange(idx) {
  currentSpeedIdx.value = idx;
}

// 声音控制
const voiceBoxRef = ref(); // 声音控制最外层元素
const voiceProgressBox = ref(); // 声音控制条元素
const curVoiceProgressH = ref('100%'); // 当前音量在
const currentVolume = ref(1);
// 单击声音控制条
function onVoicePorgressBarClick(event) {
  const clientY = event.clientY;
  setVolume(clientY);
}
// 拖动滑块
function onDragVoiceBall(event) {
  event.preventDefault();
  document.onmousemove = e => {
    e.preventDefault();
    const clientY = e.clientY;
    setVolume(clientY);
  };
  // 抬起鼠标，结束移动事件
  document.onmouseup = () => {
    document.onmousemove = null;
    document.onmouseup = null;
  };
}
// 设置音量
function setVolume(clientY) {
  // 18 为声音控制条bottom:10px padding-bottom:8px
  let offsetY = getEleOffsetTop(voiceBoxRef.value) - 18;
  const totalH = voiceProgressBox.value.offsetHeight;
  let curVoice = ((offsetY - clientY) / totalH).toFixed(2);
  curVoice = curVoice <= 0 ? 0 : curVoice >= 1 ? 1 : curVoice;
  curVoiceProgressH.value = `${curVoice * 100}%`;
  currentVolume.value = Number(curVoice);
}

// 全屏
const isFullScreen = ref(false);
function onVideoFunllScreenChange() {
  isFullScreen.value = !isFullScreen.value;
  emits('onFullScreenChange', isFullScreen.value);
}

// 手动暂停视频方法并向外暴露
function videoPause() {
  myVideo?.value?.pause();
}
defineExpose({ videoPause });
</script>

<style lang="less" scoped>
.video-box {
  position: relative;
  display: flex;
  align-items: center;
  overflow: hidden;
  background: #000;
  video {
    width: v-bind('props.width');
    height: v-bind('props.height');
    position: relative;
    z-index: 1;
    &.full-screen {
      width: 100vw;
      height: 100vh;
    }
  }
  .play-btn {
    width: 85px;
    height: 85px;
    position: absolute;
    top: 50%;
    left: 50%;
    background: url('../../assets/images/play-btn.png');
    background-size: 100%;
    z-index: 9;
    transform: translate(-50%, -50%);
  }
  .pause-mask {
    position: absolute;
    top: 0;
    right: 0;
    bottom: 0;
    left: 0;
    background: rgba(0, 0, 0, 0.5);
    z-index: 8;
  }
  .icon-loading {
    position: absolute;
    top: 50%;
    left: 50%;
    margin-top: -45px;
    margin-left: -45px;
    width: 90px;
    height: 90px;
    z-index: 8;
    background: conic-gradient(transparent 30%, #fff 100%);
    -webkit-mask: radial-gradient(closest-side, transparent 85%, #fff 0% 100%, transparent 100%);
    animation: rotate 1s linear infinite;
    @keyframes rotate {
      to {
        transform: rotate(360deg);
      }
    }
  }
  .video-bottom-box {
    position: absolute;
    left: 0;
    bottom: 18px;
    z-index: 999;
    padding: 0 24px;
    width: 100%;
    box-sizing: border-box;
    .video-control {
      display: flex;
      align-items: center;
      width: 100%;
      .bottom-btn {
        width: 24px;
        height: 24px;
        background-size: 100%;
        cursor: pointer;
        &.play {
          background-image: url('../../assets/images/icon_play.png');
        }
        &.pause {
          background-image: url('../../assets/images/icon_pause.png');
        }
        &.voice {
          margin: 0 16px;
          background-image: url('../../assets/images/icon_voice.png');
        }
        &.mute {
          margin: 0 16px;
          background-image: url('../../assets/images/icon_mute.png');
        }
        &.full-screen {
          background-image: url('../../assets/images/icon_full_screen.png');
        }
        &.quit {
          background-image: url('../../assets/images/icon_full_screen_quit.png');
        }
      }
      .time-text {
        margin: 0 16px;
        font-size: 16px;
        font-weight: 500;
        color: #fff;
        &.play-time {
          margin-right: 26px;
        }
      }
      .progress-bar-box {
        position: relative;
        display: flex;
        align-items: center;
        flex: 1;
        height: 6px;
        background-color: rgba(255, 255, 255, 0.4);
        border-radius: 6px;
        cursor: pointer;
        .progress-bar-main {
          position: absolute;
          width: v-bind(progressBarMainW);
          height: 100%;
          background-color: #fff;
          z-index: 1;
          border-radius: 6px;
        }
        .progress-bar-ball {
          position: absolute;
          left: v-bind(progressBarBallLeft);
          top: 50%;
          transform: translateY(-50%);
          width: 20px;
          height: 20px;
          background: #fff;
          border-radius: 20px;
          z-index: 1;
        }
        .progress-bar-load {
          position: absolute;
          width: v-bind(progressBarLoadW);
          height: 100%;
          background-color: #fff;
          z-index: 0;
          border-radius: 6px;
        }
      }
      .play-speed {
        position: relative;
        width: 36px;
        text-align: center;
        font-size: 16px;
        color: #fff;
        line-height: 1;
        cursor: pointer;
        &:hover {
          .speed-list {
            display: block;
          }
        }
        .speed-list {
          position: absolute;
          top: 0;
          left: 50%;
          transform: translate(-50%, -100%);
          z-index: 8;
          display: none;
          padding-bottom: 10px;
          .inner {
            background: rgba(0, 0, 0, 0.3);
            border-radius: 8px;
            overflow: hidden;
            .speed-item {
              padding: 7px 10px;
              font-size: 16px;
              color: #fff;
              font-weight: 500;
              cursor: pointer;
              &:hover {
                background: rgba(0, 0, 0, 0.2);
              }
              &.actived {
                color: var(--themecolor);
              }
            }
          }
        }
      }
      .voice {
        position: relative;
        &:hover {
          .voice-container {
            display: block;
          }
        }
        .voice-container {
          position: absolute;
          top: 0;
          left: 50%;
          transform: translate(-50%, -100%);
          z-index: 8;
          display: none;
          padding-bottom: 10px;
          .inner {
            padding: 8px;
            background: rgba(0, 0, 0, 0.3);
            border-radius: 8px;
            overflow: hidden;
            .voice-progress-bar {
              position: relative;
              width: 4px;
              height: 78px;
              background: rgba(255, 255, 255, 0.4);
              border-radius: 4px;
              .progress-bar-main {
                position: absolute;
                bottom: 0;
                height: v-bind(curVoiceProgressH);
                width: 100%;
                background-color: #fff;
                z-index: 1;
                border-radius: 4px;
              }
              .progress-bar-ball {
                position: absolute;
                left: 50%;
                bottom: v-bind(curVoiceProgressH);
                margin-bottom: -5px;
                transform: translateX(-50%);
                width: 10px;
                height: 10px;
                background: #fff;
                border-radius: 10px;
                z-index: 1;
              }
            }
          }
        }
      }
    }
  }
}
</style>
